﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Xenta.Utils;

namespace Xenta.Operations
{
    /// <summary>
    /// Exposes the report operation interface.
    /// </summary>
    /// <remarks>
    /// The central part of the reporting system. 
    /// This kind of operations collects the required 
    /// data and saves it into the OutStream stream. The
    /// result of operation is the total elapsed time in 
    /// milliseconds.
    /// </remarks>
    public interface IReportOperation : IOperation<Int64>
    {
        #region Properties

        /// <summary>
        /// Gets or sets the operation specific properties.
        /// </summary>
        IDictionary<String, String> Properties
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the report MIME type.
        /// </summary>
        string MimeType
        {
            get;
        }

        /// <summary>
        /// Gets or sets the data stream.
        /// </summary>
        Stream OutStream
        {
            get;
            set;
        }

        #endregion
    }

    /// <summary>
    /// Represents the report query operation.
    /// </summary>
    public abstract class ReportOperation : Operation<Int64>, IReportOperation
    {
        #region Properties

        /// <summary>
        /// Gets or sets the operation specific properties.
        /// </summary>
        public IDictionary<String, String> Properties
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the report MIME type.
        /// </summary>
        public abstract string MimeType
        {
            get;
        }

        /// <summary>
        /// Gets or sets the data stream.
        /// </summary>
        public Stream OutStream
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override Err Validate(IUnitOfWork uow)
        {
            if(OutStream == null)
                return Err.Of(this).NotValid("OutStream");
            if(!OutStream.CanWrite)
                return Err.Of(this).Cannot("Write");
            return base.Validate(uow);
        }

        protected override void Work(IUnitOfWork uow, out long result)
        {
            var timer = new Stopwatch();
            timer.Start();
            Report(uow);
            timer.Stop();
            result = timer.ElapsedMilliseconds;
        }

        /// <summary>
        /// Collects the required data and fills the result.
        /// </summary>
        /// <param name="uow">The unit of work.</param>
        protected abstract void Report(IUnitOfWork uow);

        #endregion
    }
}
